/**
 * ____________________ *
 *  ____ ____ ____ _  _ *
 *  |___ [__] |--< |\/| *
 * ____________________ *
 *
 * THE CORM PROJECT
 *
 * This file may only be used in accordance with the
 * terms of the Academic Free License ("AFL") v. 3.0,
 * as published by the Open Software Initiative.  A
 * copy of this license is provided in this source
 * release, and may be viewed online at:
 *
 * (http://www.opensource.org/licenses/afl-3.0.php)
 */
package org.eremite.corm.product;

import org.eremite.corm.Archetype;

import javax.measure.unit.Unit;
import javax.measure.unit.DerivedUnit;
import javax.measure.converter.UnitConverter;
import java.util.Set;
import java.util.HashSet;

import sun.reflect.generics.reflectiveObjects.NotImplementedException;

public class ProductInstance extends DerivedUnit<ProductType> {

    private String name;
    private String description;
    private SerialNumber serialNumber;
    private ProductType productType;
    private Set<ProductFeatureInstance> features = new HashSet<ProductFeatureInstance>();
    private Price price;
    private Batch batch;
    private long reservationId;
    private int reservationStatus;

    public ProductInstance() {}

    public ProductInstance(ProductType type) {
        setProductType(type);
        setName(type.getName());
        setDescription(type.getDescription());
    }

    // ***** Methods Required by DerivedUnit ******************

    public Unit<? super ProductType> getStandardUnit() {
        return ProductType.BASE_UNIT;
    }

    public UnitConverter toStandardUnit() {

        // TODO: we need to be able to convert from individual product unit
        // instances to weights, volumes, and other measurements of the product.
        // Thus, we could convert from "100 yards of rope" to "pounds of rope".
        // This requires that we have a metric profile of each product, which
        // includes weight, volume, length, width, height, etc.

        // TODO: we need to be able to convert from a product to the products
        // that it is made of.  For instance, a can of coca-cola is made out
        // of a certain amount of aluminum.  If you reprocess a can, you can
        // get a specific amount of aluminum back out of it.  This requires
        // an optional material profile for each product.  Materials are a
        // type of product.


        throw new NotImplementedException();
    }

    public int hashCode() {
        return name.hashCode();
    }

    public boolean equals(Object object) {
        return object.hashCode() == this.hashCode();
    }

    // ********************************************************

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String desc) {
        this.description = desc;
    }

    public SerialNumber getSerialNumber() {
        return serialNumber;
    }

    public void setSerialNumber(SerialNumber serialNumber) {
        this.serialNumber = serialNumber;
    }

    public ProductType getProductType() {
        return productType;
    }

    public void setProductType(ProductType productType) {
        this.productType = productType;
    }

    public Set<ProductFeatureInstance> getFeatures() {
        return features;
    }

    public void setFeatures(Set<ProductFeatureInstance> features) {
        this.features = features;
    }

    /**
     * The existence of this method inside of ProductType is highly
     * irregular.  I can see how, in the context of their original
     * rule context ideas, it might work.  But I think the rules
     * should be completely external to the CORM platform, and so
     * Price should probably be, at the very least, external to the
     * Product Archetype Pattern.  It seems like a "price" could
     * only exist in the context of a bid or sale order.  There
     * could be "listed prices" inside of a product catalog, but
     * the price would be mapped to the product types or instances,
     * and certainly not be a member of the product instances. I will
     * likely remove this method from the class before tagging a
     * release.
     * @return
     */
    public Price getPrice() {
        return price;
    }

    public void setPrice(Price price) {
        this.price = price;
    }

    public Batch getBatch() {
        return batch;
    }

    public void setBatch(Batch batch) {
        this.batch = batch;
    }

    public long getReservationID() {
        return reservationId;
    }

    public void setReservationID(long reservationId) {
        this.reservationId = reservationId;
    }

    public int getReservationStatus() {
        return reservationStatus;
    }

    public void setReservationStatus(int reservationStatus) {
        this.reservationStatus = reservationStatus;
    }
}
